/**
 * Copyright 2008 Adam Ruggles.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package kiff.entity;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Transient;

import kiff.security.Permission;

import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

/**
 * Forum Permission.
 * @author Adam
 * @version $Id: ForumPermission.java 71 2008-11-26 21:03:06Z a.ruggles $
 */
@Embeddable
public class ForumPermission implements Permission {
	/**
	 * Can create posts for a given forum if bit is set.
	 */
	public static final int POST_CREATE = 1 << 1;

	/**
	 * Can create a post but it requires approval before it will be displayed.
	 * You must have POST_CREATE before this is in effect.
	 */
	public static final int POST_CREATE_REQUIRES_APPROVAL = 1 << 2;

	/**
	 * Can delete all posts for a given forum if bit is set.
	 */
	public static final int POST_DELETE_ALL = 1 << 3;

	/**
	 * Can delete your own posts for a given forum if bit is set.
	 */
	public static final int POST_DELETE_OWN = 1 << 4;

	/**
	 * Can edit your all posts for a given forum if bit is set.
	 */
	public static final int POST_EDIT_ALL = 1 << 5;

	/**
	 * Can edit your own posts for a given forum if bit is set.
	 */
	public static final int POST_EDIT_OWN = 1 << 6;

	/**
	 * Serial Version UID.
	 */
	private static final long serialVersionUID = 2969906243206641952L;

	/**
	 * Can create new topics for a given forum if bit is set.
	 */
	public static final int TOPIC_CREATE = 1 << 7;

	/**
	 * Can create a announcement topic for a given forum if bit is set.
	 * You must have TOPIC_CREATE before this is in effect.
	 */
	public static final int TOPIC_CREATE_ANNOUNCE = 1 << 8;

	/**
	 * Can create a topic but it requires approval before it will be displayed.
	 * You must have TOPIC_CREATE before this is in effect.
	 */
	public static final int TOPIC_CREATE_REQUIRES_APPROVAL = 1 << 9;

	/**
	 * Can create a sticky topic for a given forum if bit is set.  You must have TOPIC_CREATE before this is in effect.
	 */
	public static final int TOPIC_CREATE_STICKY = 1 << 10;

	/**
	 * Can delete any topic for a given forum if bit is set.
	 */
	public static final int TOPIC_DELETE_ALL = 1 << 11;

	/**
	 * Can delete your own topic for a given forum if bit is set.
	 */
	public static final int TOPIC_DELETE_OWN = 1 << 12;

	/**
	 * Can lock any topic for a given forum if bit is set.
	 */
	public static final int TOPIC_LOCK_ALL = 1 << 13;

	/**
	 * Can lock your own topic for a given forum if bit is set.
	 */
	public static final int TOPIC_LOCK_OWN = 1 << 14;

	/**
	 * Permission value. The value represents 32 bits for each permission.
	 */
	private int value;

	/**
	 * Default Constructor.
	 */
	public ForumPermission() {
		value = 0;
	}

	/**
	 * Constructor that takes a permission value.
	 * @param value the permission value to set.
	 */
	public ForumPermission(final int value) {
		this.value = value;
	}

	/**
	 * Constructor that takes a list of values.
	 * @param values A list of values.
	 */
	public ForumPermission(final int ... values) {
		for (int bitValue : values) {
			addPermission(bitValue);
		}
	}

	/**
	 * Adds a bit value permission using logical or.
	 * @param bitValue The bit value permission.
	 */
	public void addPermission(final int bitValue) {
		this.value |= bitValue;
	}

	/**
	 * {@inheritDoc}
	 * @see kiff.security.Permission#check(kiff.security.Permission)
	 */
	public boolean check(final Permission permission) {
		if (this == permission) {
			return true;
		}
		if (!(permission instanceof ForumPermission)) {
			return false;
		}
		ForumPermission rhs = (ForumPermission) permission;
		if (rhs.getValue() == 0 && this.value != 0) {
			return false;
		}
		System.out.println("Checking bitwise permission values.");
		// Bitwise and operator to see if the given permission bits are set.
		return ((this.value & rhs.getValue()) == rhs.getValue());
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof ForumPermission)) {
			return false;
		}
		ForumPermission rhs = (ForumPermission) obj;
		return this.value == rhs.getValue();
	}

	/**
	 * Returns the permission value.
	 * @return the permission value to return.
	 */
    @Column(name = "permission")
	public int getValue() {
		return value;
	}

	/**
	 * {@inheritDoc}
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return new HashCodeBuilder(1, 41)
			.append(value)
			.toHashCode();
	}

	/**
	 * Returns true if this permission grants the user the ability to create an announcement topic.
	 * @return True if this permission grants the user the ability to create an announcement topic.
	 */
	@Transient
	public boolean isCreateAnnounceTopic() {
		return ((this.value & TOPIC_CREATE_ANNOUNCE) == TOPIC_CREATE_ANNOUNCE);
	}

	/**
	 * Returns true if this permission grants the user the ability to create a post.
	 * @return True if this permission grants the user the ability to create a post.
	 */
	@Transient
	public boolean isCreatePost() {
		return ((this.value & POST_CREATE) == POST_CREATE);
	}

	/**
	 * Returns true if this permission requires the user to have all posts require approval.
	 * @return True if this permission requires the user to have all posts require approval.
	 */
	@Transient
	public boolean isCreatePostRequiresApproval() {
		return ((this.value & POST_CREATE_REQUIRES_APPROVAL) == POST_CREATE_REQUIRES_APPROVAL);
	}

	/**
	 * Returns true if this permission grants the user the ability to create a sticky topic.
	 * @return True if this permission grants the user the ability to create a sticky topic.
	 */
	@Transient
	public boolean isCreateStickyTopic() {
		return ((this.value & TOPIC_CREATE_STICKY) == TOPIC_CREATE_STICKY);
	}

	/**
	 * Returns true if this permission grants the user the ability to create a topic.
	 * @return True if this permission grants the user the ability to create a topic.
	 */
	@Transient
	public boolean isCreateTopic() {
		return ((this.value & TOPIC_CREATE) == TOPIC_CREATE);
	}

	/**
	 * Returns true if this permission requires the user to have all topics require approval.
	 * @return True if this permission requires the user to have all topics require approval.
	 */
	@Transient
	public boolean isCreateTopicRequiresApproval() {
		return ((this.value & TOPIC_CREATE_REQUIRES_APPROVAL) == TOPIC_CREATE_REQUIRES_APPROVAL);
	}

	/**
	 * Returns true if this permission grants the user the ability to delete their own posts.
	 * @return True if this permission grants the user the ability to delete their own posts.
	 */
	@Transient
	public boolean isDeleteOwnPost() {
		return ((this.value & POST_DELETE_OWN) == POST_DELETE_OWN);
	}

	/**
	 * Returns true if this permission grants the user the ability to delete their own topics.
	 * @return True if this permission grants the user the ability to delete their own topics.
	 */
	@Transient
	public boolean isDeleteOwnTopic() {
		return ((this.value & TOPIC_DELETE_OWN) == TOPIC_DELETE_OWN);
	}

	/**
	 * Returns true if this permission grants the user the ability to delete all posts.
	 * @return True if this permission grants the user the ability to delete all posts.
	 */
	@Transient
	public boolean isDeletePost() {
		return ((this.value & POST_DELETE_ALL) == POST_DELETE_ALL);
	}

	/**
	 * Returns true if this permission grants the user the ability to delete all topics.
	 * @return True if this permission grants the user the ability to delete all topics.
	 */
	@Transient
	public boolean isDeleteTopic() {
		return ((this.value & TOPIC_DELETE_ALL) == TOPIC_DELETE_ALL);
	}

	/**
	 * Returns true if this permission grants the user the ability to edit their own posts.
	 * @return True if this permission grants the user the ability to edit their own posts.
	 */
	@Transient
	public boolean isEditOwnPost() {
		return ((this.value & POST_EDIT_OWN) == POST_EDIT_OWN);
	}

	/**
	 * Returns true if this permission grants the user the ability to edit all posts.
	 * @return True if this permission grants the user the ability to edit all posts.
	 */
	@Transient
	public boolean isEditPost() {
		return ((this.value & POST_EDIT_ALL) == POST_EDIT_ALL);
	}

	/**
	 * Returns true if this permission grants the user the ability to lock their own topics.
	 * @return True if this permission grants the user the ability to lock their own topics.
	 */
	@Transient
	public boolean isLockOwnTopic() {
		return ((this.value & TOPIC_LOCK_OWN) == TOPIC_LOCK_OWN);
	}

	/**
	 * Returns true if this permission grants the user the ability to lock all topics.
	 * @return True if this permission grants the user the ability to lock all topics.
	 */
	@Transient
	public boolean isLockTopic() {
		return ((this.value & TOPIC_LOCK_ALL) == TOPIC_LOCK_ALL);
	}

	/**
	 * Removes a bit value permission using logical and.
	 * @param bitValue The bit value permission.
	 */
	public void removePermission(final int bitValue) {
		this.value &= ~bitValue;
	}

	/**
	 * Sets the permission that grants the user the ability to create announcement topics.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setCreateAnnounceTopic(final boolean flag) {
		if (flag) {
			addPermission(TOPIC_CREATE_ANNOUNCE);
		} else {
			removePermission(TOPIC_CREATE_ANNOUNCE);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to create a post.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setCreatePost(final boolean flag) {
		if (flag) {
			addPermission(POST_CREATE);
		} else {
			removePermission(POST_CREATE);
		}
	}

	/**
	 * Sets the permission that requires the user to have all posts require approval.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setCreatePostRequiresApproval(final boolean flag) {
		if (flag) {
			addPermission(POST_CREATE_REQUIRES_APPROVAL);
		} else {
			removePermission(POST_CREATE_REQUIRES_APPROVAL);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to create a sticky topic.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setCreateStickyTopic(final boolean flag) {
		if (flag) {
			addPermission(TOPIC_CREATE_STICKY);
		} else {
			removePermission(TOPIC_CREATE_STICKY);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to create a topic.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setCreateTopic(final boolean flag) {
		if (flag) {
			addPermission(TOPIC_CREATE);
		} else {
			removePermission(TOPIC_CREATE);
		}
	}

	/**
	 * Sets the permission that requires the user to have all topics require approval.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setCreateTopicRequiresApproval(final boolean flag) {
		if (flag) {
			addPermission(TOPIC_CREATE_REQUIRES_APPROVAL);
		} else {
			removePermission(TOPIC_CREATE_REQUIRES_APPROVAL);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to delete their own posts.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setDeleteOwnPost(final boolean flag) {
		if (flag) {
			addPermission(POST_DELETE_OWN);
		} else {
			removePermission(POST_DELETE_OWN);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to delete their own topics.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setDeleteOwnTopic(final boolean flag) {
		if (flag) {
			addPermission(TOPIC_DELETE_OWN);
		} else {
			removePermission(TOPIC_DELETE_OWN);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to delete all posts.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setDeletePost(final boolean flag) {
		if (flag) {
			addPermission(POST_DELETE_ALL);
		} else {
			removePermission(POST_DELETE_ALL);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to delete all topics.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setDeleteTopic(final boolean flag) {
		if (flag) {
			addPermission(TOPIC_DELETE_ALL);
		} else {
			removePermission(TOPIC_DELETE_ALL);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to edit their own posts.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setEditOwnPost(final boolean flag) {
		if (flag) {
			addPermission(POST_EDIT_OWN);
		} else {
			removePermission(POST_EDIT_OWN);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to edit all posts.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setEditPost(final boolean flag) {
		if (flag) {
			addPermission(POST_EDIT_ALL);
		} else {
			removePermission(POST_EDIT_ALL);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to lock their own topics.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setLockOwnTopic(final boolean flag) {
		if (flag) {
			addPermission(TOPIC_LOCK_OWN);
		} else {
			removePermission(TOPIC_LOCK_OWN);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to lock all topics.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setLockTopic(final boolean flag) {
		if (flag) {
			addPermission(TOPIC_LOCK_ALL);
		} else {
			removePermission(TOPIC_LOCK_ALL);
		}
	}

	/**
	 * Sets the permission value.
	 * @param value the value to set.
	 */
	public void setValue(final int value) {
		this.value = value;
	}

	/**
	 * {@inheritDoc}
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return new ToStringBuilder(this)
			.append("hex", Integer.toHexString(this.value))
			.append("new post", (this.value & POST_CREATE) == POST_CREATE)
			.append("new topic", (this.value & TOPIC_CREATE) == TOPIC_CREATE)
			.toString();
	}
}
